1. Technical Field
The present invention is directed to an improved data processing system and, in particular, an improved mechanism for determining optimum placement of privileged code locations in existing code.
2. Description of Related Art
In Javar™ Development Kit (JDK™) version 1.1, local applications and correctly digitally signed remote programs were generally trusted to have full access to vital system resources, such as the file system. Unsigned remote programs were not trusted and could access only limited resources. A security manager was responsible for determining which resource accesses were allowed.
In the Java™ 2 platform, the security architecture is policy-based and allows for fine-rained access control. In Java™ 2, when code is loaded by the class loader, it is assigned to a protection domain that contains a collection of “permissions” based on the security policy currently in effect. Each permission specifies a permitted access to a particular resource, such as “read” and “write” access to a specified file or directory, or “connect” access to a given host and port. The policy, specifying which permissions are available for cod. from various signers and/or locations, can be initialized from an external configurable policy file. Unless a permission is explicitly granted to code, that code cannot access the resource that is protected by that permission. These concepts of permission and policy enable the Java™ 2 runtime environment to offer fine-grain, highly configurable, flexible, and extensible access control. Such access control can be specified not only for applets, but also for all Java™ code including but not limited to applications, JavaBeans™, and servlets.
The Javar™ 2 security architecture imposes the constraint that whenever a protected resource access is attempted, each class whose method is in the execution stack is checked for the required permission to access that resource. The security policy would be ineffective if code with insufficient permissions were able to invoke code with more permissions and by doing so, access system resources that it should not access by virtue of its own protection domain.
However, there is a case where this rule does not apply. If some code on the thread, i.e. methods on an execution stack, is granted the requested permission and is marked as privileged, then none of the previous callers are checked for the required permission. To mark code as privileged, it is necessary to make a call to the java.security.AccessController.doPrivileged( ) method. A piece of code that is marked as privileged is enabled to temporarily grant other code in the thread stack permissions that otherwise would not have been granted by virtue of their protection domains.
The doPrivileged( ) method was introduced in the Java™ 2 platform to avoid client code from requiring the permissions that library code, which is more trusted, may require. For example, an underlying Application Program Interface (API) method can be invoked by client code to open a socket connection. Whatever code is found on the thread of execution when the socket connection is opened will need to be granted a SocketPermission. However, before opening the socket connection, that method writes to a log file that a socket connection is going to be opened. The library code needs a FilePermission to do that, but it would not make sense to impose the requirement that the client code also have that FilePermission. To prevent the propagation of the FilePermission requirement, the code that writes to the log file must be wrapped in a doPrivileged( ) method call.
An example of how privileged code works is shown in FIG. 5. FIG. 5 illustrates a thread stack in which classes are called in a downward direction. Thus, for example, class 1 calls class 2 and class 2 calls class 3, and so on. The last class called in the thread stack is typically a call to the method AccessController. checkPermission( ). The checkPermission( ) method traverses the thread stack from the bottom of the stack to the top of the stack checking each method's class' permissions to make sure that they each have the required permissions to access a protected resource.
Assume that class 3 calls the doPrivileged( ) method. The doPrivileged( ) method basically stops the checkPermission( ) method from continuing its checks beyond that class. In this way, the doPrivileged( ) method call effectively grants the privileges necessary to access the protected resource to the classes higher up in the thread stack. Thus, only classes called after doPrivileged( ), i.e. lower in the stack, need have the required privilege to access the protected resources.
Once library code has been written, it is often difficult, if not impossible, to manually predetermine which portions should be wrapped in doPrivileged( ) calls. Developers have to manually review all of their code and/or run sample client code against their libraries to find out when that client code requires unnecessary permissions, and from there argue that a call to doPrivileged( ) is required in their library. However, especially when a large amount of library code is involved, this activity can be very tedious and error prone. If a call to doPrivileged( ) is necessary, but is not detected during the manual review of the code or the testing phase, the resulting code will be unstable and client code may invoke a particular path of execution that will generate a SecurityException. On the other hand, if a call to doPrivileged( ) is mistakenly inserted in a place where it is not required, client code will be temporarily granted unnecessary permissions, thus violating the “Principle of Least Privilege” and opening a security hole.
This problem shows up particularly when library code that was written in JDK™ 1.0 and 1.1 platforms, where the described authorization mechanism was absent, is ported to Java™ 2. In this case, any calls to doPrivileged( ) must be inserted from scratch.
Thus, it would be beneficial to have an apparatus and method that automatically determines where a call to doPrivileged( ) should be made in existing code. Furthermore, it would be beneficial to have an apparatus and method that automatically inserts a call to doPrivileged( ) in existing code and generates a new class or method that includes proper privileges without granting unnecessary privileges.